#include <ximera/scripting/lua/virtualmachine.hpp>
#include <ximera/common/utils.hpp>
#include <ximera/logger.hpp>

#include <luabind/dependency_policy.hpp>
#include <luabind/operator.hpp>

#include <string>

namespace ximera { namespace scripting { namespace lua
{
    VirtualMachine::VirtualMachine()
        : _state(lua_open())
    {
        luaL_openlibs(_state);
        luabind::open(_state);

        bindMathLib();
        bindXmlLib();
    }

    VirtualMachine::~VirtualMachine()
    {
        lua_close(_state);
    }

    Language VirtualMachine::language() const
    {
        return Language::Lua;
    }

    void VirtualMachine::run(SharedPtr<IScript> const& script)
    {
        run(script.get());
    }

    void VirtualMachine::run(IScript* script)
    {
        Script* luaScript = static_cast<Script*>(script);
        if (!luaScript)
            XIMERA_THROW(InvalidParamException, L"Script is null");

        run(luaScript->_data);

        luaScript->_isLoaded = true;
    }

    void VirtualMachine::run(String const& data)
    {
        run(string_util::wstr2str(data));
    }

    void VirtualMachine::grabError()
    {
        std::string error(std::string(lua_tostring(_state, -1), lua_strlen(_state, -1)));
        lua_pop(_state, 1);

        _lastError = string_util::str2wstr(error);
    }

    void VirtualMachine::run(std::string const& data)
    {
        if (luaL_loadstring(_state, data.c_str()))
        {
            grabError();
            XIMERA_THROW(CompilerException, L"Script had syntax errors: " + _lastError);
        }

        if (lua_pcall(_state, 0, 0, 0))
        {
            grabError();
            XIMERA_THROW(CompilerException, L"Script had runtime errors: " + _lastError);
        }
    }    
}}}